package com.yizisu.playerlibrary.impl

import android.content.Context
import android.media.AudioManager
import androidx.media.AudioFocusRequestCompat
import com.yizisu.playerlibrary.IYzsPlayer
import com.yizisu.playerlibrary.PlayerFactory
import com.yizisu.playerlibrary.helper.PlayerModel
import com.yizisu.playerlibrary.helper.SimplePlayerListener
import kotlinx.coroutines.CoroutineScope

internal abstract class BaseYzsPlayer<Model : PlayerModel>(internal val context: Context) :
    IYzsPlayer<Model> {

    /**
     * 播放倍速
     */
    private var _speed = 1f

    /**
     * 当前播放模式，支持四种
     */
    private var currentLoopMode = PlayerFactory.LOOP_MODO_NONE

    /**
     * 是否需要定时器
     */
    private var canOnTick = true

    /**
     * 设置当前索引
     */
    var currentIndex
        get() = info.currentIndex
        set(value) {
            val count = playModelList.count()
            info.currentIndex = if (count == 0) {
                0
            } else {
                when (currentLoopMode) {
                    PlayerFactory.LOOP_MODO_SINGLE -> {
                        info.currentIndex
                    }
                    PlayerFactory.LOOP_MODO_LIST -> {
                        if (value < 0) {
                            count - 1
                        } else {
                            if (value >= count) {
                                0
                            } else {
                                value
                            }
                        }
                    }
                    PlayerFactory.LOOP_MODO_SHUFF -> {
                        IntRange(0, count - 1).random()
                    }
                    else -> {
                        if (value < 0) {
                            0
                        } else {
                            if (value >= count) {
                                count - 1
                            } else {
                                value
                            }
                        }
                    }
                }
            }
        }

    //监听器集合
    private val playerListener = mutableListOf<SimplePlayerListener<Model>>()


    private var tickTask: TickTask? = null

    /**
     * 启动定时任务
     */
    fun startTick() {
        if (!canOnTick) {
            return
        }
        val tickTask = this.tickTask
        if (tickTask?.isRunning == true) {
            return
        }
        if (tickTask != null) {
            tickTask.start()
            return
        }
        this.tickTask = TickTask.start(getTickPeriod(), getTickOnThread(), ::runTick)
    }

    /**
     * 关闭当时任务
     */
    fun cancelTick() {
        tickTask?.cancel()
    }

    private suspend fun runTick(scope: CoroutineScope) {
        if (playModelList.isNotEmpty()) {
            currentPlayModel?.let { model ->
                doPlayerListener {
                    tickOnMainThread(model, it)
                    it.onTick(model, scope)
                }
            }
        }
    }

    protected fun tickOnMainThread(model: Model, listener: SimplePlayerListener<Model>) {
        model._totalDuration = totalDuration
        model._currentDuration = currentDuration
        model._currentBufferDuration = currentBufferDuration
        listener.onTick(model)
    }

    protected var info = IYzsPlayer.Info<Model>(mutableListOf(), 0)

    //是否支持处理音频焦点
    //若处理，则有焦点才播放，失去焦点停止播放
    private var audioFocusHelper: AudioFocusHelperCompat? = null

    //当前播放列表集合
    protected val playModelList: MutableList<Model>
        get() = info.playModes

    //当前播放的model
    val currentPlayModel: Model?
        get() {
            return if (currentIndex < playModelList.count() && currentIndex >= 0) {
                playModelList[currentIndex]
            } else {
                null
            }
        }


    override fun prepare(
        models: MutableList<Model>,
        playIndex: Int,
        isStopLastMedia: Boolean,
        positionMs: Long/*当前播放进度*/,
        playWhenReady: Boolean
    ) {
        if (playWhenReady) {
            play()
        }
        playModelList.clear()
        playModelList.addAll(models)
        info.currentIndex = playIndex
        doPlayerListener {
            it.onPlayerListChange(playModelList)
        }
    }

    override fun setVideoSpeed(speed: Float) {
        _speed = speed
        doPlayerListener {
            it.onSpeedChange(speed)
        }
    }

    override fun getVideoSpeed(): Float {
        return _speed
    }

    override fun onDestroy() {
        super.onDestroy()
        tickTask?.onDestroy()
        doPlayerListener {
            it.onListenerRemove(currentPlayModel, it)
            //回调播放器销魂
            it.onPlayerDestroy(this, currentPlayModel)
        }
        playModelList.forEach {
            it.onDestroy()
        }
        playModelList.clear()
        playerListener.clear()
        abandonAudioFocus()
    }

    final override fun addPlayerListener(listener: SimplePlayerListener<Model>) {
        if (!playerListener.contains(listener)) {
            playerListener.add(listener)
            listener.onListenerAdd(currentPlayModel, listener)
        }
    }

    final override fun removePlayerListener(listener: SimplePlayerListener<Model>) {
        if (playerListener.contains(listener)) {
            playerListener.remove(listener)
            listener.onListenerRemove(currentPlayModel, listener)
        }
    }

    final override fun getCurrentModel(): Model? = currentPlayModel

    final override fun getAllPlayModel(): List<Model> {
        return playModelList
    }

    final override fun getCurrentPlayIndex(): Int = currentIndex

    final override fun getRepeatMode(): Int {
        return currentLoopMode
    }

    final override fun setRepeatMode(mode: Int) {
        currentLoopMode = mode
        if (mode == PlayerFactory.LOOP_MODO_SINGLE) {
            setSingleModelRepeatModel(PlayerFactory.REPEAT_MODE_ALL)
        } else {
            setSingleModelRepeatModel(PlayerFactory.REPEAT_MODE_OFF)
        }
    }

    /**
     * 回调播放器
     */
    private val listenerTemp = mutableListOf<SimplePlayerListener<Model>>()

    inline fun doPlayerListener(model: Function1<SimplePlayerListener<Model>, Unit>) {
        listenerTemp.clear()
        listenerTemp.addAll(playerListener)
        //用新的集合，防止循环的时候移除和添加监听导致异常
        listenerTemp.forEach {
            model.invoke(it)
        }
    }

    final override fun setAudioForceEnable(enable: Boolean) {
        if (enable) {
            if (audioFocusHelper == null) {
                audioFocusHelper =
                    object : AudioFocusHelperCompat(context, getAudioForceListener()) {
                        override fun buildFocusRequest(): AudioFocusRequestCompat {
                            return onCreateAudioFocusRequestCompat()
                        }
                    }
            }
        } else {
            abandonAudioFocus()
            audioFocusHelper = null
        }
    }

    /**
     * 请求焦点
     * 返回值是否启用焦点处理
     */
    internal fun requestAudioFocus(): Boolean {
        audioFocusHelper?.requestAudioFocus()
        return audioFocusHelper != null
    }

    /**
     * 中断焦点
     * 返回值是否启用焦点处理
     */
    private fun abandonAudioFocus(): Boolean {
        audioFocusHelper?.abandonAudioFocus()
        return audioFocusHelper != null
    }

    /**
     * 获取音频焦点监听
     */
    internal abstract fun getAudioForceListener(): AudioManager.OnAudioFocusChangeListener

    /**
     * 如果添加生命周期
     * 当不可见的时候，暂停播放
     */
    override fun onStop() {
        super.onStop()
        pause()
    }

    override fun play() {
        doPlayerListener {
            it.onPlay(true, currentPlayModel)
        }
    }

    override fun pause() {
        abandonAudioFocus()
        doPlayerListener {
            it.onPause(false, currentPlayModel)
        }
    }

    override fun addPlayModel(mode: Model) {
        addPlayModel(0, mode)
    }

    override fun addPlayModel(index: Int, mode: Model) {
        if (index <= getCurrentPlayIndex()) {
            currentIndex++
        }
        playModelList.add(index, mode)
        mode.onAddedToPlayerModes(index)
        doPlayerListener {
            it.onPlayerListChange(getAllPlayModel())
        }
    }

    override fun setPlayerInfo(newInfo: IYzsPlayer.Info<Model>) {
        info = newInfo
        doPlayerListener {
            it.onPlayerListChange(getAllPlayModel())
        }
    }

    override fun removePlayModel(index: Int) {
        val list = getAllPlayModel()
        if (index >= 0 && index < list.count()) {
            val model = list[index]
            removePlayModel(model)
        }
    }

    override fun removePlayModel(mode: Model) {
        val current = currentPlayModel
        val isPlaying = isPlaying()
        val list = playModelList
        val index = list.indexOf(mode)
        if (index < getCurrentPlayIndex() && index >= 0) {
            currentIndex--
        }
        list.remove(mode)
        mode.onRemovedFromPlayerModes(index)
        doPlayerListener {
            it.onPlayerListChange(list)
        }
        if (mode == current) {
            seekTo(0, index)
            if (isPlaying) {
                play()
            } else {
                pause()
            }
        }
    }

    override fun addPlayModels(modes: MutableList<Model>) {
        addPlayModels(0, modes)
    }

    override fun addPlayModels(index: Int, modes: MutableList<Model>) {
        if (index <= getCurrentPlayIndex()) {
            currentIndex += modes.count()
        }
        playModelList.addAll(index, modes)
        doPlayerListener {
            it.onPlayerListChange(getAllPlayModel())
        }
    }

    override fun canOnTick(can: Boolean) {
        canOnTick = can
        if (can) {
            if (isPlaying()) {
                startTick()
            }
        } else {
            cancelTick()
        }
    }

    /**
     * 改变播放状态
     */
    protected open fun changePlayStatus(isPlaying: Boolean) {
        if (isPlaying) {
            startTick()
        } else {
            cancelTick()
        }
    }

    abstract fun getTickPeriod(): Long

    abstract fun getTickOnThread(): Boolean

    abstract fun onCreateAudioFocusRequestCompat(): AudioFocusRequestCompat
}